#include "Comm.hpp"
#include <memory>
#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "InetAddr.hpp"
#include "Thread.hpp"
#include <pthread.h>
using namespace std;

void Usage(const string &process)
{
    cout<<"you should use two arg"<<process<<endl;
}
class ThreadData
{
public:
    ThreadData(int sock,struct sockaddr_in &server):_sockfd(sock),_serveraddr(server)
    {

    }
    ~ThreadData(){}
    int _sockfd;
    InetAddr _serveraddr;
};
void RecverRoutine(ThreadData& td)
{
    char buffer[4096];
    while(true)
    {
        struct sockaddr_in temp;
        socklen_t len=sizeof(temp);
        ssize_t n=recvfrom(td._sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);//输出型参数
        if(n>0)
        {
            buffer[n]=0;
            cerr<<buffer<<endl;
        }
        else
        {
            break;
        }
    }
}
void SenderRoutine(ThreadData& td)
{
    while(true)
    {
        string inbuffer;
        cout<<"please Enter#";
        getline(cin,inbuffer);
        auto server=td._serveraddr.GetAddr();
        ssize_t n=sendto(td._sockfd,inbuffer.c_str(),inbuffer.size(),0,(struct sockaddr*)&server,sizeof(server));
        if(n<=0)
        {
            cout<<"send error"<<endl;
        }
    }
}

//./udp_server 8888
int main(int argc,char *argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        return 1;
    }
    string serverip=argv[1];//ip号,接下来是端口号
    uint16_t serverport=stoi(argv[2]);

    //创建socket
    //udp是全双工的，所以在发送消息的时候同样可以接受
    int sock=socket(AF_INET,SOCK_DGRAM,0);
    if(sock<0)
    {
        cerr<<"socket error"<<strerror(errno)<<endl;
        return 2;
    }
    cout<<"create socket success"<<sock<<endl;
    //客户端不需要显式进行bind操作。
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(serverport);
    server.sin_addr.s_addr=inet_addr(serverip.c_str());

    ThreadData td(sock,server);
    Thread<ThreadData> recever("recver",RecverRoutine,td);
    Thread<ThreadData> sender("sender",SenderRoutine,td);
    recever.Start();
    sender.Start();
    recever.Join();
    sender.Join();
    close(sock);
    return 0;
}
